


<template>
  <div class="ai-chat" :class="{ 'dark': isDark }">
    <!-- 顶部导航栏 -->
    <header class="bg-white dark:bg-gray-800 shadow-md sticky top-0 z-50 transition-all duration-300">
      <div class="container mx-auto px-4 py-3 flex items-center justify-between">
        <div class="flex items-center space-x-2">
          <i class="fa fa-comment text-primary text-2xl"></i>
          <h1 class="text-xl font-bold text-gray-800 dark:text-white">智能聊天助手</h1>
        </div>
        <div class="flex items-center space-x-4">
          <button @click="toggleTheme" class="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
            <i class="fa fa-moon-o dark:hidden text-gray-600"></i>
            <i class="fa fa-sun-o hidden dark:block text-yellow-400"></i>
          </button>
          <button @click="clearAllHistory" class="px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors">
            <i class="fa fa-trash-o mr-1"></i> 清空历史
          </button>
        </div>
      </div>
    </header>

    <!-- 主内容区 -->
    <main class="flex-1 container mx-auto px-4 py-6 flex flex-col md:flex-row gap-6">
      <!-- 左侧聊天历史 -->
      <aside class="w-full md:w-80 bg-white dark:bg-gray-800 rounded-xl shadow-md p-4 flex flex-col transition-all duration-300">
        <h2 class="text-lg font-semibold text-gray-800 dark:text-white mb-4">聊天历史</h2>
        <div class="flex-1 overflow-y-auto scrollbar-hide space-y-2">
          <div 
            v-for="chat in chatHistory" 
            :key="chat.id"
            class="p-3 rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex items-center"
            :class="{ 'bg-gray-100 dark:bg-gray-700': currentChatId === chat.id }"
            @click="loadChat(chat.id)"
          >
            <i class="fa fa-comment-o mr-2 text-primary"></i>
            <span class="flex-1 truncate">{{ chat.title || '新对话' }}</span>
            <span class="text-xs text-gray-500 dark:text-gray-400">{{ formatTime(chat.timestamp) }}</span>
          </div>
        </div>
      </aside>

      <!-- 右侧聊天区域 -->
      <section class="flex-1 bg-white dark:bg-gray-800 rounded-xl shadow-md flex flex-col transition-all duration-300">
        <!-- 聊天消息区 -->
        <div class="flex-1 p-4 overflow-y-auto scrollbar-hide space-y-4" ref="messagesContainer">
          <div 
            v-for="(message, index) in currentMessages" 
            :key="index"
            :class="message.role === 'user' ? 'user-message' : 'assistant-message'"
          >
            <div class="max-w-3xl mx-auto flex items-start">
              <div 
                class="w-8 h-8 rounded-full flex items-center justify-center text-white mr-3 flex-shrink-0"
                :class="message.role === 'user' ? 'bg-gray-600' : 'bg-primary'"
              >
                <i :class="message.role === 'user' ? 'fa fa-user' : 'fa fa-robot'"></i>
              </div>
              <div class="flex-1">
                <div class="text-sm font-medium text-gray-800 dark:text-white">
                  {{ message.role === 'user' ? '你' : '智能助手' }}
                </div>
                <div 
                  class="text-gray-700 dark:text-gray-300 mt-1 p-3 rounded-lg"
                  :class="message.role === 'user' ? 'bg-primary/10' : 'bg-gray-100 dark:bg-gray-700'"
                >
                  <div v-if="message.contentType === 'text'" class="prose dark:prose-invert prose-sm max-w-none">
                    <p v-html="parseMessageContent(message.content)"></p>
                  </div>
                  <div v-else-if="message.contentType === 'image'">
                    <img 
                      :src="message.content" 
                      alt="上传的图片" 
                      class="max-w-full h-auto rounded-lg shadow-md hover-scale"
                    >
                  </div>
                  <div v-else-if="message.contentType === 'audio'">
                    <audio controls class="w-full">
                      <source :src="message.content" type="audio/mpeg">
                      您的浏览器不支持音频播放。
                    </audio>
                  </div>
                  <div v-else-if="message.contentType === 'video'">
                    <video controls class="w-full rounded-lg shadow-md">
                      <source :src="message.content" type="video/mp4">
                      您的浏览器不支持视频播放。
                    </video>
                  </div>
                  <div v-else class="prose dark:prose-invert prose-sm max-w-none">
                    <p>{{ message.content }}</p>
                  </div>
                </div>
                <div class="text-xs text-gray-500 dark:text-gray-400 mt-1">
                  {{ formatTime(message.timestamp) }}
                </div>
              </div>
            </div>
          </div>
          
          <!-- 加载中动画 -->
          <div v-if="isStreaming" class="assistant-message">
            <div class="max-w-3xl mx-auto flex items-start">
              <div class="w-8 h-8 rounded-full bg-primary flex items-center justify-center text-white mr-3 flex-shrink-0">
                <i class="fa fa-robot"></i>
              </div>
              <div class="flex-1">
                <div class="text-sm font-medium text-gray-800 dark:text-white">智能助手</div>
                <div class="text-gray-700 dark:text-gray-300 mt-1 p-3 rounded-lg bg-gray-100 dark:bg-gray-700">
                  <div class="animate-pulse">
                    <div class="h-3 bg-gray-300 dark:bg-gray-600 rounded w-16 mb-2"></div>
                    <div class="h-3 bg-gray-300 dark:bg-gray-600 rounded w-32 mb-2"></div>
                    <div class="h-3 bg-gray-300 dark:bg-gray-600 rounded w-24"></div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- 输入区域 -->
        <div class="p-4 border-t border-gray-200 dark:border-gray-700">
          <!-- 文件预览 -->
          <div v-if="selectedFiles.length > 0" class="mb-3">
            <div class="p-3 bg-gray-100 dark:bg-gray-700 rounded-lg flex flex-wrap gap-3">
              <div 
                v-for="(file, index) in selectedFiles" 
                :key="index"
                class="flex items-center justify-between w-full md:w-auto md:flex-1 min-w-[200px]"
              >
                <div class="flex items-center">
                  <i 
                    :class="getIconClass(file.type)" 
                    class="text-primary mr-2"
                  ></i>
                  <span class="text-sm truncate max-w-[150px]">{{ file.name }}</span>
                </div>
                <button @click="removeFile(index)" class="text-red-500 hover:text-red-700 ml-2">
                  <i class="fa fa-times"></i>
                </button>
              </div>
            </div>
          </div>
          
          <div class="flex items-end gap-2">
            <div class="relative">
              <input 
                type="file" 
                ref="fileInput"
                @change="handleFileUpload"
                accept="image/*,audio/*,video/*"
                multiple
                class="hidden"
              >
              <button 
                class="p-3 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
                :disabled="isStreaming"
                @click="triggerFileInput"
              >
                <i class="fa fa-paperclip text-gray-600 dark:text-gray-300"></i>
              </button>
            </div>
            <textarea 
              v-model="userInput"
              @input="adjustTextareaHeight"
              class="flex-1 p-3 bg-gray-100 dark:bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary dark:text-white resize-none transition-all"
              rows="1"
              :placeholder="getPlaceholder()"
            ></textarea>
            <button 
              @click="sendMessage"
              class="p-3 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
              :disabled="isStreaming || (!userInput.trim() && !selectedFiles.length)"
            >
              <i class="fa fa-paper-plane-o"></i>
            </button>
          </div>
        </div>
      </section>
    </main>

    <!-- 页脚 -->
    <footer class="bg-white dark:bg-gray-800 py-4 border-t border-gray-200 dark:border-gray-700 transition-all duration-300">
      <div class="container mx-auto px-4 text-center text-gray-600 dark:text-gray-400 text-sm">
        <p>© 2025 智能聊天助手 | 由 <a href="#" class="text-primary hover:underline">AI团队</a> 开发</p>
      </div>
    </footer>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, watch } from 'vue';
import { useDark, useToggle } from '@vueuse/core';

// 状态管理
const messagesContainer = ref(null);
const fileInput = ref(null);
const userInput = ref('');
const selectedFiles = ref([]);
const isStreaming = ref(false);
const currentChatId = ref(Date.now().toString());
const currentMessages = ref([]);
const chatHistory = ref([]);
const isDark = useDark();
const toggleDark = useToggle(isDark);

// 初始化
onMounted(() => {
  loadChatHistory();
  loadChat(currentChatId.value);
  adjustTextareaHeight();
  
  // 监听窗口大小变化，调整输入框
  window.addEventListener('resize', adjustTextareaHeight);
});

// 调整文本域高度
const adjustTextareaHeight = () => {
  const textarea = fileInput.value?.previousElementSibling;
  if (textarea) {
    textarea.style.height = 'auto';
    textarea.style.height = (textarea.scrollHeight) + 'px';
    
    // 限制最大高度
    if (textarea.scrollHeight > 150) {
      textarea.style.overflowY = 'auto';
      textarea.style.height = '150px';
    } else {
      textarea.style.overflowY = 'hidden';
    }
  }
};

// 触发文件选择
const triggerFileInput = () => {
  fileInput.value?.click();
};

// 处理文件上传
const handleFileUpload = (event) => {
  const files = Array.from(event.target.files || []);
  if (!files.length) return;
  
  // 限制文件数量
  if (selectedFiles.value.length + files.length > 3) {
    alert('最多只能上传3个文件');
    return;
  }
  
  // 验证文件类型
  const allowedTypes = ['image', 'audio', 'video'];
  const invalidFiles = files.filter(file => !allowedTypes.some(type => file.type.startsWith(type)));
  
  if (invalidFiles.length > 0) {
    alert('只允许上传图片、音频或视频文件');
    return;
  }
  
  // 添加新文件
  selectedFiles.value = [...selectedFiles.value, ...files];
  
  // 清空文件输入框
  event.target.value = '';
};

// 移除文件
const removeFile = (index) => {
  selectedFiles.value.splice(index, 1);
};

// 获取文件图标
const getIconClass = (fileType) => {
  if (fileType.startsWith('image')) return 'fa fa-file-image-o text-blue-500';
  if (fileType.startsWith('audio')) return 'fa fa-file-audio-o text-green-500';
  if (fileType.startsWith('video')) return 'fa fa-file-video-o text-red-500';
  return 'fa fa-file-o text-gray-500';
};

// 获取占位符文本
const getPlaceholder = () => {
  if (selectedFiles.value.length > 0) {
    const fileTypes = [...new Set(selectedFiles.value.map(file => file.type.split('/')[0]))];
    const typeNames = {
      'image': '图片',
      'audio': '音频',
      'video': '视频'
    };
    const typeDesc = fileTypes.map(type => typeNames[type] || type).join('、');
    return `已选择 ${selectedFiles.value.length} 个${typeDesc}，输入消息或直接发送...`;
  }
  return '输入消息，或上传图片、音频、视频...';
};

// 发送消息
const sendMessage = async () => {
  if (isStreaming.value) return;
  if (!userInput.value.trim() && !selectedFiles.value.length) return;
  
  // 添加用户消息
  const userMessage = {
    role: 'user',
    content: userInput.value.trim(),
    timestamp: new Date().toISOString(),
    contentType: 'text'
  };
  
  // 添加文件消息
  const fileMessages = selectedFiles.value.map(file => ({
    role: 'user',
    content: URL.createObjectURL(file),
    timestamp: new Date().toISOString(),
    contentType: file.type.split('/')[0],
    originalName: file.name
  }));
  
  // 更新消息列表
  currentMessages.value = [
    ...currentMessages.value,
    userMessage,
    ...fileMessages
  ];
  
  // 保存聊天历史
  saveChatHistory();
  
  // 滚动到底部
  scrollToBottom();
  
  // 准备发送数据
  const formData = new FormData();
  if (userInput.value.trim()) {
    formData.append('prompt', userInput.value.trim());
  }
  selectedFiles.value.forEach(file => {
    formData.append('files', file);
  });
  formData.append('chatId', currentChatId.value);
  
  // 清空输入
  userInput.value = '';
  selectedFiles.value = [];
  adjustTextareaHeight();
  
  // 添加助手消息占位
  const assistantMessage = {
    role: 'assistant',
    content: '',
    timestamp: new Date().toISOString(),
    contentType: 'text'
  };
  currentMessages.value.push(assistantMessage);
  isStreaming.value = true;
  scrollToBottom();
  
  try {
    // 发送请求到后端
    const response = await fetch('http://localhost:8080/ai/chat', {
      method: 'POST',
      body: formData
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
   

    
  // 处理流式响应
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let accumulatedContent = '';
let done = false;

while (!done) {
  const { value, done: chunkDone } = await reader.read();
  done = chunkDone;
  
  if (!done) {
    // 解码并累积内容
    accumulatedContent += decoder.decode(value, { stream: true });
    
    // 更新消息内容
    currentMessages.value = currentMessages.value.map((msg, index) => {
      if (index === currentMessages.value.length - 1) {
        return { ...msg, content: accumulatedContent };
      }
      return msg;
    });
    
    // 滚动到底部
    scrollToBottom();
  }
}
    // 保存聊天历史
    saveChatHistory();
  } catch (error) {
    console.error('发送消息失败:', error);
    // 显示错误消息
    currentMessages.value = currentMessages.value.map((msg, index) => {
      if (index === currentMessages.value.length - 1) {
        return { 
          ...msg, 
          content: '抱歉，发生了错误，请稍后重试。错误详情: ' + error.message 
        };
      }
      return msg;
    });
  } finally {
    isStreaming.value = false;
    scrollToBottom();
  }
};

// 滚动到底部
const scrollToBottom = async () => {
  await nextTick();
  if (messagesContainer.value) {
    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
  }
};

// 解析消息内容（处理换行和链接）
const parseMessageContent = (content) => {
  if (!content) return '';
  
  // 替换换行符为<br>
  const withBreaks = content.replace(/\n/g, '<br>');
  
  // 替换URL为可点击的链接
  const withLinks = withBreaks.replace(
    /(https?:\/\/[^\s]+)/g,
    '<a href="$1" target="_blank" class="text-primary hover:underline">$1</a>'
  );
  
  return withLinks;
};

// 格式化时间
const formatTime = (timestamp) => {
  if (!timestamp) return '';
  
  const date = new Date(timestamp);
  const now = new Date();
  
  // 今天的消息显示时间
  if (date.toDateString() === now.toDateString()) {
    return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
  }
  
  // 今年的消息显示月/日
  if (date.getFullYear() === now.getFullYear()) {
    return date.toLocaleDateString([], { month: '2-digit', day: '2-digit' });
  }
  
  // 其他显示完整日期
  return date.toLocaleDateString();
};

// 加载聊天历史
const loadChatHistory = () => {
  const savedHistory = localStorage.getItem('chatHistory');
  if (savedHistory) {
    chatHistory.value = JSON.parse(savedHistory);
  } else {
    // 创建新的聊天历史
    const newChat = {
      id: currentChatId.value,
      title: '新对话',
      timestamp: new Date().toISOString()
    };
    chatHistory.value = [newChat];
    saveChatHistory();
  }
};

// 保存聊天历史
const saveChatHistory = () => {
  // 更新当前聊天的时间戳
  const chatIndex = chatHistory.value.findIndex(chat => chat.id === currentChatId.value);
  if (chatIndex !== -1) {
    chatHistory.value[chatIndex].timestamp = new Date().toISOString();
    
    // 如果有用户消息，更新标题
    const userMessages = currentMessages.value.filter(msg => msg.role === 'user' && msg.content);
    if (userMessages.length > 0) {
      chatHistory.value[chatIndex].title = userMessages[0].content.substring(0, 20) + (userMessages[0].content.length > 20 ? '...' : '');
    }
  }
  
  // 保存到本地存储
  localStorage.setItem('chatHistory', JSON.stringify(chatHistory.value));
  
  // 保存当前消息
  localStorage.setItem(`chatMessages_${currentChatId.value}`, JSON.stringify(currentMessages.value));
};

// 加载特定聊天
const loadChat = (chatId) => {
  currentChatId.value = chatId;
  
  // 从本地存储加载消息
  const savedMessages = localStorage.getItem(`chatMessages_${chatId}`);
  if (savedMessages) {
    currentMessages.value = JSON.parse(savedMessages);
  } else {
    currentMessages.value = [];
  }
  
  // 滚动到底部
  scrollToBottom();
};

// 开始新对话
const startNewChat = () => {
  const newChatId = Date.now().toString();
  const newChat = {
    id: newChatId,
    title: '新对话',
    timestamp: new Date().toISOString()
  };
  
  // 添加到聊天历史
  chatHistory.value = [newChat, ...chatHistory.value];
  saveChatHistory();
  
  // 加载新对话
  loadChat(newChatId);
};

// 清空所有历史
const clearAllHistory = () => {
  if (confirm('确定要清空所有聊天历史吗？此操作不可恢复。')) {
    // 清空本地存储
    chatHistory.value.forEach(chat => {
      localStorage.removeItem(`chatMessages_${chat.id}`);
    });
    localStorage.removeItem('chatHistory');
    
    // 重置状态
    startNewChat();
    loadChatHistory();
  }
};

// 切换主题
const toggleTheme = () => {
  toggleDark();
};

// 监听消息变化，自动保存
watch(currentMessages, () => {
  saveChatHistory();
});
</script>

<style scoped>
.ai-chat {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-color);
}

/* 消息动画 */
.user-message, .assistant-message {
  opacity: 0;
  transform: translateY(10px);
  animation: fadeIn 0.3s ease-out forwards;
}

@keyframes fadeIn {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 滚动条样式 */
.scrollbar-hide::-webkit-scrollbar {
  width: 4px;
}

.scrollbar-hide::-webkit-scrollbar-track {
  background: transparent;
}

.scrollbar-hide::-webkit-scrollbar-thumb {
  background-color: rgba(156, 163, 175, 0.5);
  border-radius: 20px;
}

.dark .scrollbar-hide::-webkit-scrollbar-thumb {
  background-color: rgba(75, 85, 99, 0.5);
}

/* 图片悬停效果 */
.hover-scale {
  transition: transform 0.2s ease-in-out;
}

.hover-scale:hover {
  transform: scale(1.02);
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}

/* 打字动画 */
.typing-animation span {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 3px;
  background-color: #333;
  border-radius: 50%;
  animation: typing 1.4s infinite ease-in-out;
}

.dark .typing-animation span {
  background-color: #fff;
}

.typing-animation span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-animation span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing {
  0%, 60%, 100% {
    transform: translateY(0);
    opacity: 0.6;
  }
  30% {
    transform: translateY(-5px);
    opacity: 1;
  }
}
</style>